package ru.spb.osll.myfit.server.execute;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.util.concurrent.ExecutorService;

import org.easymock.EasyMockSupport;
import org.junit.Before;
import org.junit.Test;

import ru.spb.osll.myfit.common.PageExecutingResult;
import ru.spb.osll.myfit.common.PageExecutingResult.PageExecutingState;

public class PageExecutingServiceImplTest extends EasyMockSupport {

  private PageExecutorFactory pageExecutorfactory;
  private ExecutorService executorService;
  
  @Before
  public void setUp() {
    pageExecutorfactory = createStrictMock(PageExecutorFactory.class);
    executorService = createStrictMock(ExecutorService.class);
  }

  @Test
  public void testStartExecuting() throws Exception {
  
    PageExecutingServiceImpl pageExecutingService = new TestPageExecutingServiceImpl(pageExecutorfactory, executorService);

    PageExecutor firstPageExecutor = createMock(PageExecutor.class);
    PageExecutor secondPageExecutor = createMock(PageExecutor.class);

    PageExecutingResult expectedResult1 = new PageExecutingResult("1");
    expectedResult1.setState(PageExecutingState.PROGRESS);
    
    expect(pageExecutorfactory.createPageExecutor("firstTestPage")).andReturn(
        firstPageExecutor);
    expect(firstPageExecutor.getPageExecutingResult()).andReturn(
        expectedResult1);
    expect(firstPageExecutor.getId()).andReturn("1");
    executorService.execute(firstPageExecutor);
    expectLastCall();

    PageExecutingResult expectedResult2 = new PageExecutingResult("2");
    expectedResult2.setState(PageExecutingState.NOT_STARTED);
    
    expect(pageExecutorfactory.createPageExecutor("secondTestPage")).andReturn(
        secondPageExecutor);
    expect(secondPageExecutor.getPageExecutingResult()).andReturn(
        expectedResult2);
    expect(secondPageExecutor.getId()).andReturn("2");

    executorService.execute(secondPageExecutor);
    expectLastCall();
    replayAll();

    PageExecutingResult result1 = pageExecutingService.executePage("firstTestPage");
    PageExecutingResult result2 = pageExecutingService.executePage("secondTestPage");

    assertEquals(PageExecutingState.PROGRESS, result1.getState());
    assertEquals(PageExecutingState.NOT_STARTED, result2.getState());
    assertEquals("1", result1.getID());
    assertEquals("2", result2.getID());
    verifyAll();
  }

  @Test
  public void testGetPageExecutingResult() throws Exception {
    PageExecutingServiceImpl pageExecutingService = new TestPageExecutingServiceImpl(pageExecutorfactory, executorService);

    PageExecutor firstPageExecutor = createMock(PageExecutor.class);
    PageExecutor secondPageExecutor = createMock(PageExecutor.class);

    PageExecutingResult expectedProgressResult = new PageExecutingResult("1");
    expectedProgressResult.setState(PageExecutingState.PROGRESS);
    
    expect(pageExecutorfactory.createPageExecutor("firstTestPage")).andReturn(
        firstPageExecutor);
    expect(firstPageExecutor.getPageExecutingResult()).andReturn(
        expectedProgressResult);
    expect(firstPageExecutor.getId()).andReturn("1");
    executorService.execute(firstPageExecutor);
    expectLastCall();
    
    PageExecutingResult expectedFinishResult = new PageExecutingResult("2");
    expectedFinishResult.setState(PageExecutingState.FINISH);
    expect(pageExecutorfactory.createPageExecutor("secondTestPage")).andReturn(
        secondPageExecutor);
    expect(secondPageExecutor.getPageExecutingResult()).andReturn(
        expectedFinishResult);

    executorService.execute(secondPageExecutor);
    expectLastCall();

    PageExecutingResult expectedResult = new PageExecutingResult("1");
    expectedResult.setState(PageExecutingState.FINISH);
    expect(firstPageExecutor.getPageExecutingResult())
        .andReturn(expectedResult);

    replayAll();

    pageExecutingService.executePage("firstTestPage");
    pageExecutingService.executePage("secondTestPage");

    PageExecutingResult result1 = pageExecutingService.getExecutingResult("1");
    PageExecutingResult result2 = pageExecutingService.getExecutingResult("2");

    assertNotNull(result1);
    assertEquals("1", result1.getID());
    assertEquals(PageExecutingState.FINISH, result1.getState());
    assertNull(result2);

    result1 = pageExecutingService.getExecutingResult("1");
    assertNull(result1);

    verifyAll();
  }
  
  @SuppressWarnings("serial")
  public class TestPageExecutingServiceImpl extends PageExecutingServiceImpl {
    
    public TestPageExecutingServiceImpl(PageExecutorFactory factory, ExecutorService executor) {
      m_pageExecutorFactory = factory;
      m_executorService = executor;
    }
    
    @Override
    protected void createParams() {
      
    }
  }

}
